﻿using SCG.General;
using SCG.Prism;
using SCG.Prism.Server;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace SCGMasterServer
{
    public class SVCommandModule : CustomCommandProcessor, IComparer<PrismUser>
    {
        //initialize
        public override void Initialize(PrismServer server)
        {
            //generate the scenario string
            string path = server.BasePath + @"\Scenarios\";
            if (Directory.Exists(path))
            {
                Tokenizer tok = new Tokenizer();
                string[] files = Directory.GetFiles(path);
                tok.AppendToken(files.Length);
                foreach (string fileName in files)
                {
                    string source = File.ReadAllText(fileName);
                    string scenName = System.IO.Path.GetFileNameWithoutExtension(fileName);
                    tok.AppendToken(scenName);
                    tok.AppendToken(source);
                }
                _scenString = tok.Result;
            }
        }

        //custom commands sent by SV client
        public override void ProcessCustomCommand(PrismServer server, PrismGuest guest, string commandName, string commandParams)
        {
            switch (commandName)
            {
                case "SVLogin":
                    {
                        //send them the authorized scenario source code
                        guest.CustomCommand("SVScenarios", _scenString);
                    }
                    break;
                case "SVGameEnded":
                    {
                        //parse game details
                        List<PrismUser> winners = new List<PrismUser>();
                        List<PrismUser> losers = new List<PrismUser>();
                        Dictionary<PrismUser, double> _ratings = new Dictionary<PrismUser, double>();
                        Tokenizer tok = new Tokenizer(commandParams);
                        string scenName = tok.TokenString;
                        int numPlayers = tok.TokenInt;
                        while (numPlayers > 0)
                        {
                            string playerName = tok.TokenString;
                            bool human = tok.TokenBoolean;
                            bool victor = tok.TokenBoolean;
                            if (human)
                            {
                                PrismUser user = server.Storage.FindUser(playerName);
                                _ratings[user] = user.GetRating("SV");
                                if (victor)
                                    winners.Add(user);
                                else
                                    losers.Add(user);
                            }
                            numPlayers--;
                        }

                        if (winners.Count > 0 && losers.Count > 0)
                        {
                            //winners gain points for each human they defeated, but divided by the number of allies
                            foreach (PrismUser winner in winners)
                            {
                                double oldRating = _ratings[winner];
                                double points = 0;
                                foreach (PrismUser loser in losers)
                                {
                                    double newRating = RatingCalculator.CalculateRating(oldRating, _ratings[loser], true);
                                    points += (newRating - oldRating);
                                }
                                points /= winners.Count;
                                winner.SetRating("SV", oldRating + points);
                                server.Storage.StoreUserInfo(winner);
                                server.BroadcastUserInfoChanges(winner);
                            }

                            //losers lose points for each human they lost to, divided by the number of enemies
                            foreach (PrismUser loser in losers)
                            {
                                double oldRating = _ratings[loser];
                                double pointsLost = 0;
                                foreach (PrismUser winner in winners)
                                {
                                    double newRating = RatingCalculator.CalculateRating(oldRating, _ratings[winner], false);
                                    pointsLost += (oldRating - newRating); 
                                }
                                pointsLost /= winners.Count;
                                loser.SetRating("SV", oldRating - pointsLost);
                                server.Storage.StoreUserInfo(loser);
                                server.BroadcastUserInfoChanges(loser);
                            }
                        }
                    }
                    break;
                case "SVBrainRankings":
                    {
                        SendBrainRankings(server, guest);
                    }
                    break;
                case "SVBrainDuel":
                    {
                        string fileName = server.BasePath + @"\BrainRankings.txt";
                        string[] rankings = null;
                        if (File.Exists(fileName))
                            rankings = File.ReadAllLines(fileName);
                        Dictionary<string, double> brainRankings = new Dictionary<string, double>();
                        if (rankings != null)
                        {
                            foreach (string line in rankings)
                            {
                                string[] tokens = line.Split('|');
                                brainRankings[tokens[0]] = Double.Parse(tokens[1]);
                            }
                        }
                        Tokenizer tok = new Tokenizer(commandParams);
                        while (tok.HasTokens)
                        {
                            string winner = tok.TokenString;
                            string loser = tok.TokenString;
                            double rankWinner = 1200.0;
                            if (brainRankings.ContainsKey(winner))
                                rankWinner = brainRankings[winner];
                            double rankLoser = 1200.0;
                            if (brainRankings.ContainsKey(loser))
                                rankLoser = brainRankings[loser];
                            brainRankings[winner] = RatingCalculator.CalculateRating(rankWinner, rankLoser, true);
                            brainRankings[loser] = RatingCalculator.CalculateRating(rankLoser, rankWinner, false);
                        }
                        int idx = 0;
                        string[] newRatings = new string[brainRankings.Count];
                        foreach (string key in brainRankings.Keys)
                        {
                            string line = key + "|" + brainRankings[key];
                            newRatings[idx] = line;
                            idx++;
                        }
                        File.WriteAllLines(fileName, newRatings);
                        SendBrainRankings(server, guest);
                    }
                    break;
                case "SVStarLordRankings":
                    {
                        List<PrismUser> users = server.Storage.GetUserList();
                        List<PrismUser> ratedUsers = new List<PrismUser>();
                        foreach (PrismUser user in users)
                            if (user.GetDetail("SVRating") != "")
                                ratedUsers.Add(user);
                        ratedUsers.Sort(this);
                        Tokenizer tok = new Tokenizer();
                        foreach (PrismUser user in ratedUsers)
                            tok.AppendToken(user.ToString());
                        string result = tok.Result;
                        guest.CustomCommand("SVStarLordRankings", result);
                    }
                    break;
            }
        }

        //send brain rankings to guest
        private void SendBrainRankings(PrismServer server, PrismGuest guest)
        {
            string fileName = server.BasePath + @"\BrainRankings.txt";
            if (File.Exists(fileName))
            {
                string contents = File.ReadAllText(fileName);
                guest.CustomCommand("SVBrainRankings", contents);
            }
        }

        //private members
        private string _scenString = "";

        //sort users by rating
        public int Compare(PrismUser x, PrismUser y)
        {
            return y.GetRating("SV").CompareTo(x.GetRating("SV"));
        }
    }
}
